#!/bin/bash
#
# clandestine.googlecode.com
#

readonly TABFNAME="resistance"
readonly SEDLINE='/^#/d; /^[ \\t]$/d'
readonly FIELDS="TARGET IFACES IPS PROTO OPTIONS"

function Debug () {
	(( $VERBOSITY )) && echo -e "$@" > /dev/stderr
}

function AddOptions () {
	OPTIONS_ARRAY+=( "$@" )
}

function TargetFill () {
	TABLE=""; CHAINS=""
	[[ "$1" ]] && TABLE="$1"
	[[ "$2" ]] && CHAINS="$2"
	[[ "$3" ]] && AddOptions "jump=$3"
	[[ "$4" ]] && [[ "$TARGET_OPTIONS" ]] && AddOptions "$4=$TARGET_OPTIONS"
}

function GetChains () {
	declare -- PREFIX SUFFIX DELIM RESULT
	if [[ "$IFACES" ]]; then
		for DELIM in "-" "=" ":"; do
			read PREFIX SUFFIX <<< "${IFACES/$DELIM/ }"
			[[ "$SUFFIX" ]] && break
		done
		if [[ "$SUFFIX" ]]; then case "$DELIM" in
			"-")
				RESULT="FORWARD"
				IFACES="$PREFIX,$SUFFIX"
			;;
			"=")
				RESULT="FORWARD"
				IFACES="$PREFIX,$SUFFIX $SUFFIX,$PREFIX"
			;;
			":")
				case "$PREFIX" in
					"in" ) RESULT="INPUT";;
					"out") RESULT="OUTPUT";;
				esac
				IFACES="$SUFFIX"
			;;
		esac; else
			RESULT="INPUT OUTPUT"
		fi
	else
		RESULT="INPUT FORWARD OUTPUT"
	fi
	echo "$RESULT"
}

# ======== LET'S GET DANGEROUS ========
#
# ifupdown will set for us: IFACE LOGICAL ADDRFAM METHOD MODE PHASE VERBOSITY
[[ "$VERBOSITY" ]] || VERBOSITY="1"

declare -a IPLINES=()
OLDIFS="$IFS"
IFS=$'\n'
readonly -a RULES=( `sed "$SEDLINE" "$TABFNAME"` )
IFS="$OLDIFS"
for RULE in "${RULES[@]}"; do
	read $FIELDS <<< "$RULE"
	for VARNAME in $FIELDS; do [[ "${!VARNAME}" == '*' ]] && declare -- "$VARNAME"=""; done
	eval "declare -a OPTIONS_ARRAY=( $OPTIONS ) &> /dev/null" # eval helps to preserve quotes
	read TARGET TARGET_OPTIONS <<< "${TARGET/:/ }"
	case "$TARGET" in
		"ALIAS")
			InterfaceAlias set ${TARGET_OPTIONS/=/ }
			continue
		;;
		"POLICY")
			declare -a POLICIES=( ${TARGET_OPTIONS//,/ } )
			if (( ${#POLICIES[@]} == 3 )); then
				for POLICY in "INPUT ${POLICIES[0]}" "FORWARD ${POLICIES[1]}" "OUTPUT ${POLICIES[2]}"; do IPLINES+=( "--policy $POLICY" ); done
			else
				Debug "POLICY requires exactly three policies e.g.: POLICY:DROP,DROP,DROP"
			fi
			continue
		;;
		# FILTER TABLE              TABLE   CHAINS       TARGET      TARGET_OPTIONS
		"ACCEPT"|"DROP") TargetFill filter "`GetChains`" "$TARGET";;
		"REJECT"       ) TargetFill filter "`GetChains`" "$TARGET"   reject-with;;
		# NAT TABLE
		"PRE_DROP"     ) TargetFill nat     PREROUTING   DROP;;
		"OUT_DROP"     ) TargetFill nat     OUTPUT       DROP;;
		"POST_DROP"    ) TargetFill nat     POSTROUTING  DROP;;
		"PRE_SAME"     ) TargetFill nat     PREROUTING   SAME        to;;
		"OUT_SAME"     ) TargetFill nat     OUTPUT       SAME        to;;
		"POST_SAME"    ) TargetFill nat     POSTROUTING  SAME        to;;
		"DNAT"         ) TargetFill nat     PREROUTING   DNAT        to-destination;;
		"OUT_DNAT"     ) TargetFill nat     OUTPUT       DNAT        to-destination;;
		"REDIRECT"     ) TargetFill nat     PREROUTING   REDIRECT    to-ports;;
		"OUT_REDIRECT" ) TargetFill nat     OUTPUT       REDIRECT    to-ports;;
		"SNAT"         ) TargetFill nat     POSTROUTING "$TARGET"    to-source;;
		"MASQUERADE"   ) TargetFill nat     POSTROUTING "$TARGET"    to-ports;;
		*)
			Debug "unknown target: $TARGET, skipping line"
			continue
		;;
	esac



	read PROTO PROTO_OPTIONS <<< "${PROTO/:/ }"
	case "$PROTO" in
		"icmp")
			AddOptions "protocol=icmp"
		;;
		"tcp")
			AddOptions "protocol=tcp"

			[[ "$PROTO_OPTIONS" ]] && AddOptions "source-port=$PROTO_OPTIONS"

		;;
		"udp")
			AddOptions "protocol=udp"
		;;
		*)
:
#			AddOptions "protocol=$PROTO"
		;;
	esac



	OPTIONS=""
	for OPTION in "${OPTIONS_ARRAY[@]}"; do
		read OPTION VALUE <<< "${OPTION/=/ }"
		[[ "$OPTION" ]] && OPTIONS+="--$OPTION " # empty array elements are quite possible
		[[ "$VALUE" ]] && OPTIONS+="'$VALUE' "
	done

	for CHAIN in $CHAINS; do
		IPLINES+=( "--table $TABLE --append $CHAIN $OPTIONS" )
	done

done

# Apply the lines
for IPLINE in "${IPLINES[@]}"; do echo "$IPLINE"; done








#matches:

#addrtype        --src-type --dst-type
#ah              --ahspi
#comment         --comment
#connbytes       --connbytes --connbytes-dir --connbytes-mode
#connlimit       --connlimit-above --connlimit-mask
#connmark        --mark
#conntrack       --ctstate --ctproto --ctorigsrc --ctorigdst --ctreplsrc --ctrepldst --ctstatus --ctexpire
#dccp            --source-port --sport --destination-port --dport --dccp-types --dccp-option
#dscp            --dscp --dscp-class
#ecn             --ecn-tcp-cwr --ecn-tcp-ece --ecn-ip-ect
#esp             --espspi
#hashlimit       --hashlimit[-*]
#helper          --helper
#iprange         --src-range --dst-range
#length          --length
#limit           --limit --limit-burst
